package com.supreme.nettyapp.generalclient.mqttclient.controller;

import com.supreme.nettyapp.generalclient.mqttclient.props.MqttClientProps;
import com.supreme.nettyapp.generalclient.mqttclient.service.MqttClientService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.handler.codec.mqtt.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Random;

@RestController
@RequestMapping(value = "mqtt")
public class MqttClientController {

    @Resource
    private MqttClientProps mqttClientProps;

    @Resource
    private MqttClientService mqttClientService;

    @GetMapping(value = "connect")
    public String connect() {
        MqttFixedHeader connectFixedHeader = new MqttFixedHeader(
                MqttMessageType.CONNECT,
                false,
                MqttQoS.AT_MOST_ONCE,
                false,
                0);
        MqttConnectVariableHeader connectVariableHeader = new MqttConnectVariableHeader(
                "MQTT",
                5,
                true,
                true,
                false,
                0,
                false,
                false,
                60,
                MqttProperties.NO_PROPERTIES);
        MqttConnectPayload connectPayload = new MqttConnectPayload(
                mqttClientProps.getClientId(),
                MqttProperties.NO_PROPERTIES,
                null,
                null,
                mqttClientProps.getUsername(),
                mqttClientProps.getPassword().getBytes());
        MqttConnectMessage connectMessage = new MqttConnectMessage(connectFixedHeader, connectVariableHeader, connectPayload);

        Channel channel = mqttClientService.getChannel();
        channel.writeAndFlush(connectMessage);

        return "success";
    }

    @GetMapping(value = "subscribe/{topic}")
    public String subscribeTopic(@PathVariable(value = "topic") String topic) {
        MqttFixedHeader subscribeFixedHeader = new MqttFixedHeader(
                MqttMessageType.SUBSCRIBE,
                false,
                MqttQoS.AT_LEAST_ONCE,
                false,
                0);
        MqttMessageIdVariableHeader messageIdVariableHeader = MqttMessageIdVariableHeader.from(new Random().nextInt(65536));

        MqttSubscriptionOption mqttSubscriptionOption = new MqttSubscriptionOption(
                MqttQoS.AT_MOST_ONCE,
                false,
                false,
                MqttSubscriptionOption.RetainedHandlingPolicy.SEND_AT_SUBSCRIBE);
        MqttSubscribePayload subscribePayload = new MqttSubscribePayload(
                Collections.singletonList(new MqttTopicSubscription(topic, mqttSubscriptionOption))
        );
        MqttMessage subscribeMessage = new MqttSubscribeMessage(subscribeFixedHeader, messageIdVariableHeader, subscribePayload);
        Channel channel = mqttClientService.getChannel();
        channel.writeAndFlush(subscribeMessage);

        return "success";
    }

    @GetMapping(value = "publish/{topic}/{message}")
    public String publish(@PathVariable(value = "topic") String topic, @PathVariable(value = "message") String message) {
        ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getBytes());
        /*MqttPublishMessage mqttPublishMessage = (MqttPublishMessage) MqttMessageFactory.newMessage(
                new MqttFixedHeader(
                        MqttMessageType.PUBLISH,
                        false,
                        MqttQoS.AT_MOST_ONCE,
                        false,
                        0),
                new MqttPublishVariableHeader(topic, 0), Unpooled.wrappedBuffer(byteBuf)
        );*/

        MqttPublishMessage mqttPublishMessage = MqttMessageBuilders.publish()
                .topicName(topic)
                .retained(false)
                .qos(MqttQoS.AT_MOST_ONCE)
                .payload(Unpooled.wrappedBuffer(byteBuf))
                .build();

        mqttClientService.writeAndFlush(mqttPublishMessage);
        return "success";
    }

    @GetMapping(value = "ping")
    public String ping() {
        MqttFixedHeader fixedHeader = new MqttFixedHeader(
                MqttMessageType.PINGREQ,
                false,
                MqttQoS.AT_MOST_ONCE,
                false,
                0);
        MqttMessage mqttMessage = new MqttMessage(fixedHeader);
        mqttClientService.writeAndFlush(mqttMessage);
        return "success";
    }
}
